﻿#include "pch.h"
#if _QG_ENABLE_WIDGET
#include "qgp/qgach.h"
#include "qgp/qgaud.h"
#include "qgp/qguwgs.h"

//////////////////////////////////////////////////////////////////////////
// 위젯 분석 전용 클래스
class qgWgsReader : public qgWgs
{
public:
	bool MarkupRoot(kMlTag* root, qbWidgetContainer* ctnr)
	{
		if (!ctnr)
			return false;

		kint cnt = k_mltag_get_sub_count(root);

		for (kint i = 0; i < cnt; i++)
		{
			kMlTag* tag = k_mltag_get_sub_nth(root, i);
			qwCtrl* wg = MarkupNode(tag);

			if (wg)
			{
				if (ctnr->AddControl(wg))
					++_last_depth;

				wg->Unload();
			}
		}

		return true;
	}

	qwCtrl* MarkupNode(kMlTag* tag)
	{
		static struct WgPair
		{
			const char* name;
			qgWidgetType type;
		} s_pair[] =
		{
			{"FORM", QGW_FORM},
			{"PANEL", QGW_PANEL},
			{"DIVIDE", QGW_DIVIDE},
			{"LABEL", QGW_LABEL},
			{"BUTTON", QGW_BUTTON},
			{"SCROLL", QGW_SCROLL},
			{"LIST", QGW_LIST},
			{"COMBO", QGW_COMBO},
			{"PROGRESS", QGW_PROGRESS},
			{"TEXTLINE", QGW_TEXTLINE},
			{"RIBBONBUTTON", QGW_RIBBON_BUTTON},
			{"RIBBONCOMBO", QGW_RIBBON_COMBO},

			// 추가
			{"TEXTBOX", QGW_TEXTLINE},
		};

		// 찾기
		WgPair* pair = NULL;

		for (ksize_t i = 0; i < K_COUNTOF(s_pair); i++)
		{
			if (k_streqv(tag->name, s_pair[i].name))
			{
				pair = &s_pair[i];
				break;
			}
		}

		if (!pair)
			return NULL;

		// 만들기
		qwCtrl* wg = CreateControl(pair->type, 0, tpl::Rect(0, 0, 0, 0), NULL);
		MarkupProp(pair->type, wg, tag);

		return wg;
	}

	bool MarkupProp(qgWidgetType type, qwCtrl* wg, kMlTag* tag)
	{
		kpointer index = NULL;
		const char* name;
		const char* data;

		while (k_mltag_next_arg(tag, &index, &name, &data))
		{
			if (k_streqv(name, "ID"))
				wg->SetId(k_atoi(data));
			else if (k_streqv(name, "NAME"))
				wg->SetName(data);

			//////////////////////////////////////////////////////////////////////////
			// 상태값
			else if (k_streqv(name, "VISIBLE"))
				wg->SetVisible(k_atob(data) != 0);
			else if (k_streqv(name, "ENABLE"))
				wg->SetEnable(k_atob(data) != 0);
			else if (k_streqv(name, "FILL"))
				wg->SetFillMode(k_atob(data) != 0);
			else if (k_streqv(name, "ACCEPTBUTTON"))
				wg->SetAcceptMode(k_atob(data) != 0);
			else if (k_streqv(name, "CANCELBUTTON"))
				wg->SetCancelMode(k_atob(data) != 0);
			else if (k_streqv(name, "INPUT"))
				wg->SetInputMode(k_atob(data) != 0);
			else if (k_streqv(name, "SIZABLE"))
				wg->SetSizeMode(k_atob(data) != 0);
			else if (k_streqv(name, "MOVABLE"))
				wg->SetMoveMode(k_atob(data) != 0);
			else if (k_streqv(name, "SHADOW"))
				wg->SetShadowMode(k_atob(data) != 0);
			else if (k_streqv(name, "BORDER"))
				wg->SetBorderMode(k_atob(data) != 0);
			else if (k_streqv(name, "SUNKEN"))
				wg->SetSunkenMode(k_atob(data) != 0);
			else if (k_streqv(name, "EXTINFO"))
				wg->SetExtInfo(k_atob(data) != 0);
			else if (k_streqv(name, "READONLY"))
				wg->SetReadOnly(k_atob(data) != 0);

			//////////////////////////////////////////////////////////////////////////
			// 레이아웃
			else if (k_streqv(name, "LOCATION"))
				wg->SetLocation(ConvToPoint(data));
			else if (k_streqv(name, "SIZE"))
				wg->SetSize(ConvToPoint(data));
			else if (k_streqv(name, "BOUNDARY") || k_streqv(name, "BND"))
			{
				// 이건 그냥이 아니다 right=width, bottom=height의 의미를 갖는다
				tpl::Rect rt = ConvToRect(data);
				wg->SetBound(rt.left, rt.top, rt.right, rt.bottom);
			}
			else if (k_streqv(name, "AREA") | k_streqv(name, "RECT"))
				wg->SetBound(ConvToRect(data));

			//////////////////////////////////////////////////////////////////////////
			// 출력 속성
			else if (k_streqv(name, "IMAGE") || k_streqv(name, "TEXTURE"))
				wg->OpenTexture(data);
			//else if (k_streqv(name, "NORMALCOORD"))
			//else if (k_streqv(name, "SELECTCOORD"))
			//else if (k_streqv(name, "OVERCOORD"))
			//else if (k_streqv(name, "DISABLECOORD"))
			else if (k_streqv(name, "NORMALCOLOR"))
				wg->ReplaceColor(QGWELM_NORMAL, ConvToColor(data));
			else if (k_streqv(name, "SELECTCOLOR"))
				wg->ReplaceColor(QGWELM_SELECT, ConvToColor(data));
			else if (k_streqv(name, "OVERCOLOR"))
				wg->ReplaceColor(QGWELM_OVER, ConvToColor(data));
			else if (k_streqv(name, "DISABLECOLOR"))
				wg->ReplaceColor(QGWELM_DISABLE, ConvToColor(data));
			else if (k_streqv(name, "COLORS"))
			{
				tpl::ColorValue color(ConvToColor(data));
				wg->ReplaceColor(QGWELM_NORMAL, color);
				wg->ReplaceColor(QGWELM_SELECT, color);
				wg->ReplaceColor(QGWELM_OVER, color);
				wg->ReplaceColor(QGWELM_DISABLE, color);
			}
			else if (k_streqv(name, "SHADOWCOLOR"))
				wg->SetShadowColor(ConvToColor(data));
			else if (k_streqv(name, "BORDERCOLOR"))
				wg->SetBorderColor(ConvToColor(data));
			//else if (k_streqv(name, "FONT"))

			//////////////////////////////////////////////////////////////////////////
			// 텍스트
			else if (k_streqv(name, "TEXT"))
			{
				k_strdquote((char*)data, '\0');
				wg->SetText(data);
			}
			else if (k_streqv(name, "TEXTSIZE"))
			{
				kint size = k_atoi(data);
				if (size > 0)
					wg->SetTextSize(size);
			}
			else if (k_streqv(name, "TEXTCOLOR"))
				wg->SetTextColor(ConvToColor(data));
			else if (k_streqv(name, "TEXTALIGN"))
				wg->SetTextAlign(ConvToAlign(data));

			//////////////////////////////////////////////////////////////////////////
			// 기본 이벤트
			else if (k_streqv(name, "ONCUSTOMDRAW"))
			{
				const qwEventFunc* fn = GetCustomEvent(data);
				if (fn) wg->SetCustomDraw(*(const qwEventDrawFunc*)fn);
			}
			else if (k_streqv(name, "ONCLICK") || k_streqv(name, "ONCOMMIT"))
			{
				const qwEventFunc* fn = GetCustomEvent(data);
				if (fn) wg->SetEventClick(*fn);
			}
			else if (k_streqv(name, "ONLAYOUTCHANGED"))
			{
				const qwEventFunc* fn = GetCustomEvent(data);
				if (fn) wg->SetEventLayoutChanged(*(const qwEventLayoutFunc*)fn);
			}
			else if (k_streqv(name, "ONTEXTCHANGED"))
			{
				const qwEventFunc* fn = GetCustomEvent(data);
				if (fn) wg->SetEventTextChanged(*(const qwEventTextFunc*)fn);
			}

			//////////////////////////////////////////////////////////////////////////
			// 분리자 전용
			else if (type == QGW_DIVIDE)
			{
				if (k_streqv(name, "THICK"))
					((qwDivide*)wg)->SetThick(k_atoi(data));
				else if (k_streqv(name, "COUNT"))
					((qwDivide*)wg)->SetCount(k_atoi(data));
				else if (k_streqv(name, "DIRECTION") || k_streqv(name, "DIR"))
				{
					kint ch = k_toupper(*data);
					if (ch == 'H') ((qwDivide*)wg)->SetHorizonal();
					else if (ch == 'V') ((qwDivide*)wg)->SetVertical();
				}
				else
					k_tracef(KLV_WARNING, "qg.wgs", "line#%d, unknown argument '%s'", tag->line, name);
			}

			//////////////////////////////////////////////////////////////////////////
			// 프로그레스 전용
			else if (type == QGW_PROGRESS)
			{
				if (k_streqv(name, "MARGIN"))
					((qwProgress*)wg)->SetMargin(ConvToPoint(data));
				else if (k_streqv(name, "POSITION"))
					((qwProgress*)wg)->SetPosition(k_atoi(data));
				else if (k_streqv(name, "MIN"))
				{
					tpl::Point pt = ((qwProgress*)wg)->GetRange();
					pt.min = k_atoi(data);
					((qwProgress*)wg)->SetRange(pt);
				}
				else if (k_streqv(name, "MAX"))
				{
					tpl::Point pt = ((qwProgress*)wg)->GetRange();
					pt.max = k_atoi(data);
					((qwProgress*)wg)->SetRange(pt);
				}
				else if (k_streqv(name, "RANGE"))
					((qwProgress*)wg)->SetRange(ConvToPoint(data));
				else if (k_streqv(name, "ONPOSITIONCHANGED"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwProgress*)wg)->SetEventPositionChanged(*(const qwEventIntFunc*)fn);
				}
				else
					k_tracef(KLV_WARNING, "wg.file", "line#%d, unknown argument '%s'", tag->line, name);
			}

			//////////////////////////////////////////////////////////////////////////
			// 스크롤 전용
			else if (type == QGW_SCROLL)
			{
				if (k_streqv(name, "PAGESIZE"))
					((qwScroll*)wg)->SetPageSize(k_atoi(data));
				else if (k_streqv(name, "POSITION"))
					((qwScroll*)wg)->SetPosition(k_atoi(data));
				else if (k_streqv(name, "COUNT") || k_streqv(name, "MAX"))
					((qwScroll*)wg)->SetCount(k_atoi(data));
				else if (k_streqv(name, "ONPOSITIONCHANGED"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwScroll*)wg)->SetEventPositionChanged(*(const qwEventIntFunc*)fn);
				}
				else
					k_tracef(KLV_WARNING, "wg.file", "line#%d, unknown argument '%s'", tag->line, name);
			}

			//////////////////////////////////////////////////////////////////////////
			// 리스트 전용
			else if (type == QGW_LIST)
			{
				if (k_streqv(name, "MULTI"))
					((qwList*)wg)->SetMultiSelect(k_atob(data) != 0);
				else if (k_streqv(name, "SCROLLSIZE"))
					((qwList*)wg)->SetScrollSize(k_atoi(data));
				else if (k_streqv(name, "ITEMHEIGHT"))
					((qwList*)wg)->SetItemHeight(k_atoi(data));
				else if (k_streqv(name, "MARGIN"))
					((qwList*)wg)->SetSelectMargin(ConvToPoint(data));
				else if (k_streqv(name, "BORDER"))
					((qwList*)wg)->SetBorderSize(ConvToPoint(data));
				//else if (k_streqv(name, "SELECTIONCOLOR"))
				else if (k_streqv(name, "ONDRAGENTER"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwList*)wg)->SetEventDragEnter(*(const qwEventDragFunc*)fn);
				}
				else if (k_streqv(name, "ONDRAGLEAVE"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwList*)wg)->SetEventDragLeave(*(const qwEventDragFunc*)fn);
				}
				else if (k_streqv(name, "ONSELECTCHANGED"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwList*)wg)->SetEventSelectChanged(*(const qwEventIntFunc*)fn);
				}
				else
					k_tracef(KLV_WARNING, "wg.file", "line#%d, unknown argument '%s'", tag->line, name);
			}

			//////////////////////////////////////////////////////////////////////////
			// 콤보
			else if (type == QGW_COMBO)
			{
				if (k_streqv(name, "LENGTH") || k_streqv(name, "DROPLEN"))
					((qwCombo*)wg)->SetDropLength(k_atoi(data));
				else if (k_streqv(name, "SCROLLSIZE"))
					((qwCombo*)wg)->SetScrollSize(k_atoi(data));
				else if (k_streqv(name, "ITEMHEIGHT"))
					((qwCombo*)wg)->SetItemHeight(k_atoi(data));
				else if (k_streqv(name, "AUTOHEIGHT"))
					((qwCombo*)wg)->SetAutoHeight(k_atob(data) != 0);
				else if (k_streqv(name, "MARGIN"))
					((qwCombo*)wg)->SetSelectMargin(ConvToPoint(data));
				else if (k_streqv(name, "BORDER"))
					((qwCombo*)wg)->SetBorderSize(ConvToPoint(data));
				else if (k_streqv(name, "ONCONTEXTOPEN"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwCombo*)wg)->SetEventContextOpen(*(const qwEventBoolFunc*)fn);
				}
				else if (k_streqv(name, "ONCONTEXTCLOSE"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwCombo*)wg)->SetEventContextClose(*(const qwEventBoolFunc*)fn);
				}
				else if (k_streqv(name, "ONSELECTCHANGED"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwCombo*)wg)->SetEventSelectChanged(*(const qwEventIntFunc*)fn);
				}
				else
					k_tracef(KLV_WARNING, "wg.file", "line#%d, unknown argument '%s'", tag->line, name);
			}

			//////////////////////////////////////////////////////////////////////////
			// 텍스트
			else if (type == QGW_TEXTLINE)
			{
				if (k_streqv(name, "NUMBERONLY"))
					((qwTextLine*)wg)->SetNumberOnly(k_atob(data) != 0);
				else if (k_streqv(name, "INSERT"))
					((qwTextLine*)wg)->SetInsertMode(k_atob(data) != 0);
				//else if (k_streqv(name, "DISPLAYCOLOR"))
				//else if (k_streqv(name, "CARETCOLOR"))
				//else if (k_streqv(name, "INVERSECOLOR"))
				//else if (k_streqv(name, "SELECTIONCOLOR"))
				else if (k_streqv(name, "CARETBLINK"))
					((qwTextLine*)wg)->SetCaretBlink(k_atof(data));
				else if (k_streqv(name, "BORDER"))
					((qwTextLine*)wg)->SetBorderSize(ConvToPoint(data));
				else if (k_streqv(name, "ONTEXTCOMMAND"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwTextLine*)wg)->SetEventTextCommand(*(const qwEventBoolFunc*)fn);
				}
				else
					k_tracef(KLV_WARNING, "wg.file", "line#%d, unknown argument '%s'", tag->line, name);
			}

			//////////////////////////////////////////////////////////////////////////
			// 리본 버튼
			else if (type == QGW_RIBBON_BUTTON)
			{
				if (k_streqv(name, "DIRECTION") || k_streqv(name, "DIR"))
				{
					if (k_strnicmp(data, "HORIZ", 5) == 0)
						((qwRibbonButton*)wg)->SetDirection(QGWDIR_HORIZ);
					else if (k_strnicmp(data, "VERT", 4) == 0)
						((qwRibbonButton*)wg)->SetDirection(QGWDIR_VERT);
				}
				else
					k_tracef(KLV_WARNING, "wg.file", "line#%d, unknown argument '%s'", tag->line, name);
			}

			//////////////////////////////////////////////////////////////////////////
			// 리본 콤보
			else if (type == QGW_RIBBON_COMBO)
			{
				if (k_streqv(name, "DIRECTION") || k_streqv(name, "DIR"))
				{
					if (k_strnicmp(data, "HORIZ", 5) == 0)
						((qwRibbonButton*)wg)->SetDirection(QGWDIR_HORIZ);
					else if (k_strnicmp(data, "VERT", 4) == 0)
						((qwRibbonButton*)wg)->SetDirection(QGWDIR_VERT);
				}
				else if (k_streqv(name, "LENGTH") || k_streqv(name, "DROPLEN"))
					((qwRibbonCombo*)wg)->SetDropLength(k_atoi(data));
				else if (k_streqv(name, "SCROLLSIZE"))
					((qwRibbonCombo*)wg)->SetScrollSize(k_atoi(data));
				else if (k_streqv(name, "ITEMHEIGHT"))
					((qwRibbonCombo*)wg)->SetItemHeight(k_atoi(data));
				else if (k_streqv(name, "AUTOHEIGHT"))
					((qwRibbonCombo*)wg)->SetAutoHeight(k_atob(data) != 0);
				else if (k_streqv(name, "ONCONTEXTOPEN"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwRibbonCombo*)wg)->SetEventContextOpen(*(const qwEventBoolFunc*)fn);
				}
				else if (k_streqv(name, "ONCONTEXTCLOSE"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwRibbonCombo*)wg)->SetEventContextClose(*(const qwEventBoolFunc*)fn);
				}
				else if (k_streqv(name, "ONSELECTCHANGED"))
				{
					const qwEventFunc* fn = GetCustomEvent(data);
					if (fn) ((qwRibbonCombo*)wg)->SetEventSelectChanged(*(const qwEventIntFunc*)fn);
				}
				else
					k_tracef(KLV_WARNING, "wg.file", "line#%d, unknown argument '%s'", tag->line, name);
			}

			//////////////////////////////////////////////////////////////////////////
			// 패널
			else if (type == QGW_PANEL)
			{
				if (k_streqv(name, "BACKGROUND"))
				{
					qgTexture* tex = qgRdh::Instance->CreateTexture(data, QGTEXF_NOMIP);
					if (tex)
					{
						((qwPanel*)wg)->SetBackground(tex);
						tex->Unload();
					}
				}
				else if (k_streqv(name, "BACKCOLOR"))
					((qwPanel*)wg)->SetBackColor(ConvToColor(data));
				else
					k_tracef(KLV_WARNING, "wg.file", "line#%d, unknown argument '%s'", tag->line, name);
			}

			//////////////////////////////////////////////////////////////////////////
			// 폼
			else if (type == QGW_FORM)
			{
				if (k_streqv(name, "ICON"))
				{
					qgTexture* tex = qgRdh::Instance->CreateTexture(data, QGTEXF_NOMIP);
					if (tex)
					{
						((qwForm*)wg)->SetIcon(tex);
						tex->Unload();
					}
				}
				else if (k_streqv(name, "BACKGROUND"))
				{
					qgTexture* tex = qgRdh::Instance->CreateTexture(data, QGTEXF_NOMIP);
					if (tex)
					{
						((qwForm*)wg)->SetBackground(tex);
						tex->Unload();
					}
				}
				else if (k_streqv(name, "BACKCOLOR"))
					((qwForm*)wg)->SetBackColor(ConvToColor(data));
				//else if (k_streqv(name, "SIZECOLOR"))
				// SIZEMIN
				// SIZEMAX
				else
					k_tracef(KLV_WARNING, "wg.file", "line#%d, unknown argument '%s'", tag->line, name);
			}
		}

		// 서브
		switch ((ksize_t)type)
		{
			case QGW_FORM:
			case QGW_PANEL:
				MarkupRoot(tag, wg->GetContainer());
				break;

			case QGW_TEXTLINE:
				MarkupTextBox((qwTextLine*)wg, tag);
				break;

			case QGW_LIST:
				MarkupList((qwList*)wg, tag);
				break;

			case QGW_COMBO:
				MarkupCombo((qwCombo*)wg, tag);
				break;

			case QGW_RIBBON_COMBO:
				MarkupCombo(((qwRibbonCombo*)wg)->GetCombo(), tag);
				break;
		}

		wg->SetStatus(QGWS_NORMAL);

		return true;
	}

	void MarkupTextBox(qwTextLine* txt, kMlTag* root)
	{
		if (root->clen > 0)
			txt->SetText(root->cntx);
	}

	void MarkupList(qwList* lst, kMlTag* root)
	{
		kint cnt = k_mltag_get_sub_count(root);

		for (kint i = 0; i < cnt; i++)
		{
			kMlTag* tag = k_mltag_get_sub_nth(root, i);

			if (k_streqv(tag->name, "ITEM") && tag->clen > 0)
			{
				const char* psz = k_mltag_get_arg(tag, "TAG", NULL);
				lst->AddItem(tag->cntx, !psz ? NULL : K_CAST_INT_TO_PTR(k_atoi(psz)));
			}
		}
	}

	void MarkupCombo(qwCombo* cbo, kMlTag* root)
	{
		kint cnt = k_mltag_get_sub_count(root);

		for (kint i = 0; i < cnt; i++)
		{
			kMlTag* tag = k_mltag_get_sub_nth(root, i);

			if (k_streqv(tag->name, "ITEM") && tag->clen > 0)
			{
				const char* psz = k_mltag_get_arg(tag, "TAG", NULL);
				const char* clr = k_mltag_get_arg(tag, "COLOR", NULL);

				if (clr)
				{
					cbo->AddItem(tag->cntx, tpl::ColorValue(k_atoi(clr)),
						!psz ? NULL : K_CAST_INT_TO_PTR(k_atoi(psz)));
				}
				else
				{
					cbo->AddItem(tag->cntx, !psz ? NULL : K_CAST_INT_TO_PTR(k_atoi(psz)));
				}
			}
		}
	}

	//
	static tpl::Point ConvToPoint(const char* psz)
	{
		tpl::Point pt(0, 0);
		pt.x = k_atoi(psz);
		char* nxt = k_strchr(psz, ',');
		if (nxt)
		{
			nxt++;
			pt.y = k_atoi(nxt);
		}
		return pt;
	}

	static tpl::Rect ConvToRect(const char* psz)
	{
		tpl::Rect rt(0, 0, 0, 0);
		char* nxt;
		rt.left = k_atoi(psz);
		nxt = k_strchr(psz, ',');
		if (nxt)
		{
			nxt++;
			rt.top = k_atoi(nxt);
			nxt = k_strchr(nxt, ',');
			if (nxt)
			{
				nxt++;
				rt.right = k_atoi(nxt);
				nxt = k_strchr(nxt, ',');
				if (nxt)
				{
					nxt++;
					rt.bottom = k_atoi(nxt);
				}
			}
		}
		return rt;
	}

	static tpl::Quad ConvToQuad(const char* psz)
	{
		tpl::Quad qd(0.0f, 0.0f, 0.0f, 0.0f);
		char* nxt;
		qd.left = k_atof(psz);
		nxt = k_strchr(psz, ',');
		if (nxt)
		{
			nxt++;
			qd.top = k_atof(nxt);
			nxt = k_strchr(nxt, ',');
			if (nxt)
			{
				nxt++;
				qd.right = k_atof(nxt);
				nxt = k_strchr(nxt, ',');
				if (nxt)
				{
					nxt++;
					qd.bottom = k_atof(nxt);
				}
			}
		}
		return qd;
	}

	static tpl::ColorValue ConvToColor(const char* psz)
	{
		if (*psz == '#')
		{
			kuint cc = (kuint)k_atoi_h(psz + 1);
			if (k_strlen(psz + 1) < 7)
				cc |= 0xFF000000;
			return tpl::ColorValue(cc);
		}
		else if (k_strieqv(psz, "WHITE"))
			return tpl::ColorValues::White;
		else if (k_strieqv(psz, "BLACK"))
			return tpl::ColorValues::Black;
		else if (k_strieqv(psz, "BLUE"))
			return tpl::ColorValues::Blue;
		else if (k_strieqv(psz, "GREEN"))
			return tpl::ColorValues::Green;
		else if (k_strieqv(psz, "RED"))
			return tpl::ColorValues::Red;
		else if (k_strieqv(psz, "YELLOW"))
			return tpl::ColorValues::Yellow;
		else if (k_strieqv(psz, "CYAN"))
			return tpl::ColorValues::Cyan;
		else if (k_strieqv(psz, "MAGENTA"))
			return tpl::ColorValues::Magenta;
		else if (k_strieqv(psz, "TRANSPARENT"))
			return tpl::ColorValue(0, 0, 0, 0);
		else
		{
			kuint cc = (kuint)k_atoi(psz);
			return tpl::ColorValue(cc);
		}
	}

	static kint ConvToAlign(const char* psz)
	{
		kint ret = 0;
		char* fnd;
		for (char* tmp = (char*)psz;; tmp = fnd + 1)
		{
			if (k_strnicmp(tmp, "left", 4) == 0)         ret |= QGWALIGN_LEFT;
			else if (k_strnicmp(tmp, "right", 5) == 0)   ret |= QGWALIGN_RIGHT;
			else if (k_strnicmp(tmp, "center", 6) == 0)  ret |= QGWALIGN_CENTER;
			else if (k_strnicmp(tmp, "top", 3) == 0)     ret |= QGWALIGN_TOP;
			else if (k_strnicmp(tmp, "bottom", 6) == 0)  ret |= QGWALIGN_BOTTOM;
			else if (k_strnicmp(tmp, "vcenter", 7) == 0) ret |= QGWALIGN_VCENTER;
			fnd = k_strchr(tmp, '|');
			if (!fnd)
				break;
		}
		return ret;
	}
};

// 읽기
kint qgWgs::ReadData(kpointer readdata, kint readsize)
{
	k_return_value_if_fail(readdata, -1);

	kMlu* ml = k_mlu_new_buffer(readdata, readsize);

	if (!ml)
		return -1;

#if 0 && _SB_DEBUG_
	k_mlu_print_err(ml);
	k_mlu_print(ml);
#endif

	kint cnt = k_mlu_get_count(ml);

	for (kint i = 0; i < cnt; i++)
	{
		kMlTag* root = k_mlu_get_tag_nth(ml, i);

		if (!k_streqv(root->name, "SB"))
			continue;

		const char* proj = k_mltag_get_arg(root, "PROJECT", NULL);

		if (!proj || !k_strieqv(proj, "QG"))
			continue;

		const char* clas = k_mltag_get_arg(root, "CLASS", NULL);

		if (!clas || !k_strieqv(clas, "UI"))
			continue;

		// 실제 읽기
		static_cast<qgWgsReader*>(this)->MarkupRoot(root, this);
	}

	k_mlu_delete(ml);

	return _last_depth;
}

// 읽기
kint qgWgs::ReadFile(const char* filename)
{
	kint readsize;
	kpointer readdata = qgRdh::Instance->GetStub()->FileRead(filename, &readsize);
	k_return_value_if_fail(readdata, -1);

	kint ret = ReadData(readdata, readsize);

	k_delete(readdata);

	return ret;
}

#endif	// _QG_ENABLE_WIDGET
